1 /*
2 * Copyright (C) 2009 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.cache;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.base.Preconditions.checkState;
22
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.base.Ascii;
25 import com.google.common.base.Equivalence;
26 import com.google.common.base.MoreObjects;
27 import com.google.common.base.Supplier;
28 import com.google.common.base.Suppliers;
29 import com.google.common.base.Ticker;
30 import com.google.common.cache.AbstractCache.SimpleStatsCounter;
31 import com.google.common.cache.AbstractCache.StatsCounter;
32 import com.google.common.cache.LocalCache.Strength;
33
34 import java.util.concurrent.TimeUnit;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
37
38 import javax.annotation.CheckReturnValue;
39
40 /**
41 * <p>A builder of {@link LoadingCache} and {@link Cache} instances having any combination of the
42 * following features:
43 *
44 * <ul>
45 * <li>automatic loading of entries into the cache
46 * <li>least-recently-used eviction when a maximum size is exceeded
47 * <li>time-based expiration of entries, measured since last access or last write
48 * <li>keys automatically wrapped in {@linkplain WeakReference weak} references
49 * <li>values automatically wrapped in {@linkplain WeakReference weak} or
50 * {@linkplain SoftReference soft} references
51 * <li>notification of evicted (or otherwise removed) entries
52 * <li>accumulation of cache access statistics
53 * </ul>
54 *
55 * <p>These features are all optional; caches can be created using all or none of them. By default
56 * cache instances created by {@code CacheBuilder} will not perform any type of eviction.
57 *
58 * <p>Usage example: <pre> {@code
59 *
60 * LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
61 * .maximumSize(10000)
62 * .expireAfterWrite(10, TimeUnit.MINUTES)
63 * .removalListener(MY_LISTENER)
64 * .build(
65 * new CacheLoader<Key, Graph>() {
66 * public Graph load(Key key) throws AnyException {
67 * return createExpensiveGraph(key);
68 * }
69 * });}</pre>
70 *
71 * <p>Or equivalently, <pre> {@code
72 *
73 * // In real life this would come from a command-line flag or config file
74 * String spec = "maximumSize=10000,expireAfterWrite=10m";
75 *
76 * LoadingCache<Key, Graph> graphs = CacheBuilder.from(spec)
77 * .removalListener(MY_LISTENER)
78 * .build(
79 * new CacheLoader<Key, Graph>() {
80 * public Graph load(Key key) throws AnyException {
81 * return createExpensiveGraph(key);
82 * }
83 * });}</pre>
84 *
85 * <p>The returned cache is implemented as a hash table with similar performance characteristics to
86 * {@link ConcurrentHashMap}. It implements all optional operations of the {@link LoadingCache} and
87 * {@link Cache} interfaces. The {@code asMap} view (and its collection views) have <i>weakly
88 * consistent iterators</i>. This means that they are safe for concurrent use, but if other threads
89 * modify the cache after the iterator is created, it is undefined which of these changes, if any,
90 * are reflected in that iterator. These iterators never throw {@link
91 * ConcurrentModificationException}.
92 *
93 * <p><b>Note:</b> by default, the returned cache uses equality comparisons (the
94 * {@link Object#equals equals} method) to determine equality for keys or values. However, if
95 * {@link #weakKeys} was specified, the cache uses identity ({@code ==})
96 * comparisons instead for keys. Likewise, if {@link #weakValues} or {@link #softValues} was
97 * specified, the cache uses identity comparisons for values.
98 *
99 * <p>Entries are automatically evicted from the cache when any of
100 * {@linkplain #maximumSize(long) maximumSize}, {@linkplain #maximumWeight(long) maximumWeight},
101 * {@linkplain #expireAfterWrite expireAfterWrite},
102 * {@linkplain #expireAfterAccess expireAfterAccess}, {@linkplain #weakKeys weakKeys},
103 * {@linkplain #weakValues weakValues}, or {@linkplain #softValues softValues} are requested.
104 *
105 * <p>If {@linkplain #maximumSize(long) maximumSize} or
106 * {@linkplain #maximumWeight(long) maximumWeight} is requested entries may be evicted on each cache
107 * modification.
108 *
109 * <p>If {@linkplain #expireAfterWrite expireAfterWrite} or
110 * {@linkplain #expireAfterAccess expireAfterAccess} is requested entries may be evicted on each
111 * cache modification, on occasional cache accesses, or on calls to {@link Cache#cleanUp}. Expired
112 * entries may be counted by {@link Cache#size}, but will never be visible to read or write
113 * operations.
114 *
115 * <p>If {@linkplain #weakKeys weakKeys}, {@linkplain #weakValues weakValues}, or
116 * {@linkplain #softValues softValues} are requested, it is possible for a key or value present in
117 * the cache to be reclaimed by the garbage collector. Entries with reclaimed keys or values may be
118 * removed from the cache on each cache modification, on occasional cache accesses, or on calls to
119 * {@link Cache#cleanUp}; such entries may be counted in {@link Cache#size}, but will never be
120 * visible to read or write operations.
121 *
122 * <p>Certain cache configurations will result in the accrual of periodic maintenance tasks which
123 * will be performed during write operations, or during occasional read operations in the absence of
124 * writes. The {@link Cache#cleanUp} method of the returned cache will also perform maintenance, but
125 * calling it should not be necessary with a high throughput cache. Only caches built with
126 * {@linkplain #removalListener removalListener}, {@linkplain #expireAfterWrite expireAfterWrite},
127 * {@linkplain #expireAfterAccess expireAfterAccess}, {@linkplain #weakKeys weakKeys},
128 * {@linkplain #weakValues weakValues}, or {@linkplain #softValues softValues} perform periodic
129 * maintenance.
130 *
131 * <p>The caches produced by {@code CacheBuilder} are serializable, and the deserialized caches
132 * retain all the configuration properties of the original cache. Note that the serialized form does
133 * <i>not</i> include cache contents, but only configuration.
134 *
135 * <p>See the Guava User Guide article on <a href=
136 * "http://code.google.com/p/guava-libraries/wiki/CachesExplained">caching</a> for a higher-level
137 * explanation.
138 *
139 * @param <K> the base key type for all caches created by this builder
140 * @param <V> the base value type for all caches created by this builder
141 * @author Charles Fry
142 * @author Kevin Bourrillion
143 * @since 10.0
144 */
145 @GwtCompatible(emulated = true)
146 public final class CacheBuilder<K, V> {
147 private static final int DEFAULT_INITIAL_CAPACITY = 16;
148 private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
149 private static final int DEFAULT_EXPIRATION_NANOS = 0;
150 private static final int DEFAULT_REFRESH_NANOS = 0;
151
152 static final Supplier<? extends StatsCounter> NULL_STATS_COUNTER = Suppliers.ofInstance(
153 new StatsCounter() {
154 @Override
155 public void recordHits(int count) {}
156
157 @Override
158 public void recordMisses(int count) {}
159
160 @Override
161 public void recordLoadSuccess(long loadTime) {}
162
163 @Override
164 public void recordLoadException(long loadTime) {}
165
166 @Override
167 public void recordEviction() {}
168
169 @Override
170 public CacheStats snapshot() {
171 return EMPTY_STATS;
172 }
173 });
174 static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0);
175
176 static final Supplier<StatsCounter> CACHE_STATS_COUNTER =
177 new Supplier<StatsCounter>() {
178 @Override
179 public StatsCounter get() {
180 return new SimpleStatsCounter();
181 }
182 };
183
184 enum NullListener implements RemovalListener<Object, Object> {
185 INSTANCE;
186
187 @Override
188 public void onRemoval(RemovalNotification<Object, Object> notification) {}
189 }
190
191 enum OneWeigher implements Weigher<Object, Object> {
192 INSTANCE;
193
194 @Override
195 public int weigh(Object key, Object value) {
196 return 1;
197 }
198 }
199
200 static final Ticker NULL_TICKER = new Ticker() {
201 @Override
202 public long read() {
203 return 0;
204 }
205 };
206
207 private static final Logger logger = Logger.getLogger(CacheBuilder.class.getName());
208
209 static final int UNSET_INT = -1;
210
211 boolean strictParsing = true;
212
213 int initialCapacity = UNSET_INT;
214 int concurrencyLevel = UNSET_INT;
215 long maximumSize = UNSET_INT;
216 long maximumWeight = UNSET_INT;
217 Weigher<? super K, ? super V> weigher;
218
219 Strength keyStrength;
220 Strength valueStrength;
221
222 long expireAfterWriteNanos = UNSET_INT;
223 long expireAfterAccessNanos = UNSET_INT;
224 long refreshNanos = UNSET_INT;
225
226 Equivalence<Object> keyEquivalence;
227 Equivalence<Object> valueEquivalence;
228
229 RemovalListener<? super K, ? super V> removalListener;
230 Ticker ticker;
231
232 Supplier<? extends StatsCounter> statsCounterSupplier = NULL_STATS_COUNTER;
233
234 // TODO(fry): make constructor private and update tests to use newBuilder
235 CacheBuilder() {}
236
237 /**
238 * Constructs a new {@code CacheBuilder} instance with default settings, including strong keys,
239 * strong values, and no automatic eviction of any kind.
240 */
241 public static CacheBuilder<Object, Object> newBuilder() {
242 return new CacheBuilder<Object, Object>();
243 }
244
245 Equivalence<Object> getKeyEquivalence() {
246 return MoreObjects.firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
247 }
248
249 Equivalence<Object> getValueEquivalence() {
250 return MoreObjects.firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
251 }
252
253 /**
254 * Sets the minimum total size for the internal hash tables. For example, if the initial capacity
255 * is {@code 60}, and the concurrency level is {@code 8}, then eight segments are created, each
256 * having a hash table of size eight. Providing a large enough estimate at construction time
257 * avoids the need for expensive resizing operations later, but setting this value unnecessarily
258 * high wastes memory.
259 *
260 * @throws IllegalArgumentException if {@code initialCapacity} is negative
261 * @throws IllegalStateException if an initial capacity was already set
262 */
263 public CacheBuilder<K, V> initialCapacity(int initialCapacity) {
264 checkState(this.initialCapacity == UNSET_INT, "initial capacity was already set to %s",
265 this.initialCapacity);
266 checkArgument(initialCapacity >= 0);
267 this.initialCapacity = initialCapacity;
268 return this;
269 }
270
271 int getInitialCapacity() {
272 return (initialCapacity == UNSET_INT) ? DEFAULT_INITIAL_CAPACITY : initialCapacity;
273 }
274
275 /**
276 * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The
277 * table is internally partitioned to try to permit the indicated number of concurrent updates
278 * without contention. Because assignment of entries to these partitions is not necessarily
279 * uniform, the actual concurrency observed may vary. Ideally, you should choose a value to
280 * accommodate as many threads as will ever concurrently modify the table. Using a significantly
281 * higher value than you need can waste space and time, and a significantly lower value can lead
282 * to thread contention. But overestimates and underestimates within an order of magnitude do not
283 * usually have much noticeable impact. A value of one permits only one thread to modify the cache
284 * at a time, but since read operations and cache loading computations can proceed concurrently,
285 * this still yields higher concurrency than full synchronization.
286 *
287 * <p> Defaults to 4. <b>Note:</b>The default may change in the future. If you care about this
288 * value, you should always choose it explicitly.
289 *
290 * <p>The current implementation uses the concurrency level to create a fixed number of hashtable
291 * segments, each governed by its own write lock. The segment lock is taken once for each explicit
292 * write, and twice for each cache loading computation (once prior to loading the new value,
293 * and once after loading completes). Much internal cache management is performed at the segment
294 * granularity. For example, access queues and write queues are kept per segment when they are
295 * required by the selected eviction algorithm. As such, when writing unit tests it is not
296 * uncommon to specify {@code concurrencyLevel(1)} in order to achieve more deterministic eviction
297 * behavior.
298 *
299 * <p>Note that future implementations may abandon segment locking in favor of more advanced
300 * concurrency controls.
301 *
302 * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
303 * @throws IllegalStateException if a concurrency level was already set
304 */
305 public CacheBuilder<K, V> concurrencyLevel(int concurrencyLevel) {
306 checkState(this.concurrencyLevel == UNSET_INT, "concurrency level was already set to %s",
307 this.concurrencyLevel);
308 checkArgument(concurrencyLevel > 0);
309 this.concurrencyLevel = concurrencyLevel;
310 return this;
311 }
312
313 int getConcurrencyLevel() {
314 return (concurrencyLevel == UNSET_INT) ? DEFAULT_CONCURRENCY_LEVEL : concurrencyLevel;
315 }
316
317 /**
318 * Specifies the maximum number of entries the cache may contain. Note that the cache <b>may evict
319 * an entry before this limit is exceeded</b>. As the cache size grows close to the maximum, the
320 * cache evicts entries that are less likely to be used again. For example, the cache may evict an
321 * entry because it hasn't been used recently or very often.
322 *
323 * <p>When {@code size} is zero, elements will be evicted immediately after being loaded into the
324 * cache. This can be useful in testing, or to disable caching temporarily without a code change.
325 *
326 * <p>This feature cannot be used in conjunction with {@link #maximumWeight}.
327 *
328 * @param size the maximum size of the cache
329 * @throws IllegalArgumentException if {@code size} is negative
330 * @throws IllegalStateException if a maximum size or weight was already set
331 */
332 public CacheBuilder<K, V> maximumSize(long size) {
333 checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
334 this.maximumSize);
335 checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
336 this.maximumWeight);
337 checkState(this.weigher == null, "maximum size can not be combined with weigher");
338 checkArgument(size >= 0, "maximum size must not be negative");
339 this.maximumSize = size;
340 return this;
341 }
342
343 long getMaximumWeight() {
344 if (expireAfterWriteNanos == 0 || expireAfterAccessNanos == 0) {
345 return 0;
346 }
347 return (weigher == null) ? maximumSize : maximumWeight;
348 }
349
350 // Make a safe contravariant cast now so we don't have to do it over and over.
351 @SuppressWarnings("unchecked")
352 <K1 extends K, V1 extends V> Weigher<K1, V1> getWeigher() {
353 return (Weigher<K1, V1>) MoreObjects.firstNonNull(weigher, OneWeigher.INSTANCE);
354 }
355
356 CacheBuilder<K, V> setKeyStrength(Strength strength) {
357 checkState(keyStrength == null, "Key strength was already set to %s", keyStrength);
358 keyStrength = checkNotNull(strength);
359 return this;
360 }
361
362 Strength getKeyStrength() {
363 return MoreObjects.firstNonNull(keyStrength, Strength.STRONG);
364 }
365
366 CacheBuilder<K, V> setValueStrength(Strength strength) {
367 checkState(valueStrength == null, "Value strength was already set to %s", valueStrength);
368 valueStrength = checkNotNull(strength);
369 return this;
370 }
371
372 Strength getValueStrength() {
373 return MoreObjects.firstNonNull(valueStrength, Strength.STRONG);
374 }
375
376 /**
377 * Specifies that each entry should be automatically removed from the cache once a fixed duration
378 * has elapsed after the entry's creation, or the most recent replacement of its value.
379 *
380 * <p>When {@code duration} is zero, this method hands off to
381 * {@link #maximumSize(long) maximumSize}{@code (0)}, ignoring any otherwise-specificed maximum
382 * size or weight. This can be useful in testing, or to disable caching temporarily without a code
383 * change.
384 *
385 * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
386 * write operations. Expired entries are cleaned up as part of the routine maintenance described
387 * in the class javadoc.
388 *
389 * @param duration the length of time after an entry is created that it should be automatically
390 * removed
391 * @param unit the unit that {@code duration} is expressed in
392 * @throws IllegalArgumentException if {@code duration} is negative
393 * @throws IllegalStateException if the time to live or time to idle was already set
394 */
395 public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
396 checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns",
397 expireAfterWriteNanos);
398 checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
399 this.expireAfterWriteNanos = unit.toNanos(duration);
400 return this;
401 }
402
403 long getExpireAfterWriteNanos() {
404 return (expireAfterWriteNanos == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos;
405 }
406
407 /**
408 * Specifies that each entry should be automatically removed from the cache once a fixed duration
409 * has elapsed after the entry's creation, the most recent replacement of its value, or its last
410 * access. Access time is reset by all cache read and write operations (including
411 * {@code Cache.asMap().get(Object)} and {@code Cache.asMap().put(K, V)}), but not by operations
412 * on the collection-views of {@link Cache#asMap}.
413 *
414 * <p>When {@code duration} is zero, this method hands off to
415 * {@link #maximumSize(long) maximumSize}{@code (0)}, ignoring any otherwise-specificed maximum
416 * size or weight. This can be useful in testing, or to disable caching temporarily without a code
417 * change.
418 *
419 * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
420 * write operations. Expired entries are cleaned up as part of the routine maintenance described
421 * in the class javadoc.
422 *
423 * @param duration the length of time after an entry is last accessed that it should be
424 * automatically removed
425 * @param unit the unit that {@code duration} is expressed in
426 * @throws IllegalArgumentException if {@code duration} is negative
427 * @throws IllegalStateException if the time to idle or time to live was already set
428 */
429 public CacheBuilder<K, V> expireAfterAccess(long duration, TimeUnit unit) {
430 checkState(expireAfterAccessNanos == UNSET_INT, "expireAfterAccess was already set to %s ns",
431 expireAfterAccessNanos);
432 checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
433 this.expireAfterAccessNanos = unit.toNanos(duration);
434 return this;
435 }
436
437 long getExpireAfterAccessNanos() {
438 return (expireAfterAccessNanos == UNSET_INT)
439 ? DEFAULT_EXPIRATION_NANOS : expireAfterAccessNanos;
440 }
441
442 long getRefreshNanos() {
443 return (refreshNanos == UNSET_INT) ? DEFAULT_REFRESH_NANOS : refreshNanos;
444 }
445
446 /**
447 * Specifies a nanosecond-precision time source for use in determining when entries should be
448 * expired. By default, {@link System#nanoTime} is used.
449 *
450 * <p>The primary intent of this method is to facilitate testing of caches which have been
451 * configured with {@link #expireAfterWrite} or {@link #expireAfterAccess}.
452 *
453 * @throws IllegalStateException if a ticker was already set
454 */
455 public CacheBuilder<K, V> ticker(Ticker ticker) {
456 checkState(this.ticker == null);
457 this.ticker = checkNotNull(ticker);
458 return this;
459 }
460
461 Ticker getTicker(boolean recordsTime) {
462 if (ticker != null) {
463 return ticker;
464 }
465 return recordsTime ? Ticker.systemTicker() : NULL_TICKER;
466 }
467
468 /**
469 * Specifies a listener instance that caches should notify each time an entry is removed for any
470 * {@linkplain RemovalCause reason}. Each cache created by this builder will invoke this listener
471 * as part of the routine maintenance described in the class documentation above.
472 *
473 * <p><b>Warning:</b> after invoking this method, do not continue to use <i>this</i> cache
474 * builder reference; instead use the reference this method <i>returns</i>. At runtime, these
475 * point to the same instance, but only the returned reference has the correct generic type
476 * information so as to ensure type safety. For best results, use the standard method-chaining
477 * idiom illustrated in the class documentation above, configuring a builder and building your
478 * cache in a single statement. Failure to heed this advice can result in a {@link
479 * ClassCastException} being thrown by a cache operation at some <i>undefined</i> point in the
480 * future.
481 *
482 * <p><b>Warning:</b> any exception thrown by {@code listener} will <i>not</i> be propagated to
483 * the {@code Cache} user, only logged via a {@link Logger}.
484 *
485 * @return the cache builder reference that should be used instead of {@code this} for any
486 * remaining configuration and cache building
487 * @throws IllegalStateException if a removal listener was already set
488 */
489 @CheckReturnValue
490 public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> removalListener(
491 RemovalListener<? super K1, ? super V1> listener) {
492 checkState(this.removalListener == null);
493
494 // safely limiting the kinds of caches this can produce
495 @SuppressWarnings("unchecked")
496 CacheBuilder<K1, V1> me = (CacheBuilder<K1, V1>) this;
497 me.removalListener = checkNotNull(listener);
498 return me;
499 }
500
501 // Make a safe contravariant cast now so we don't have to do it over and over.
502 @SuppressWarnings("unchecked")
503 <K1 extends K, V1 extends V> RemovalListener<K1, V1> getRemovalListener() {
504 return (RemovalListener<K1, V1>)
505 MoreObjects.firstNonNull(removalListener, NullListener.INSTANCE);
506 }
507
508 /**
509 * Enable the accumulation of {@link CacheStats} during the operation of the cache. Without this
510 * {@link Cache#stats} will return zero for all statistics. Note that recording stats requires
511 * bookkeeping to be performed with each operation, and thus imposes a performance penalty on
512 * cache operation.
513 *
514 * @since 12.0 (previously, stats collection was automatic)
515 */
516 public CacheBuilder<K, V> recordStats() {
517 statsCounterSupplier = CACHE_STATS_COUNTER;
518 return this;
519 }
520
521 boolean isRecordingStats() {
522 return statsCounterSupplier == CACHE_STATS_COUNTER;
523 }
524
525 Supplier<? extends StatsCounter> getStatsCounterSupplier() {
526 return statsCounterSupplier;
527 }
528
529 /**
530 * Builds a cache, which either returns an already-loaded value for a given key or atomically
531 * computes or retrieves it using the supplied {@code CacheLoader}. If another thread is currently
532 * loading the value for this key, simply waits for that thread to finish and returns its
533 * loaded value. Note that multiple threads can concurrently load values for distinct keys.
534 *
535 * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be
536 * invoked again to create multiple independent caches.
537 *
538 * @param loader the cache loader used to obtain new values
539 * @return a cache having the requested features
540 */
541 public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(
542 CacheLoader<? super K1, V1> loader) {
543 checkWeightWithWeigher();
544 return new LocalCache.LocalLoadingCache<K1, V1>(this, loader);
545 }
546
547 /**
548 * Builds a cache which does not automatically load values when keys are requested.
549 *
550 * <p>Consider {@link #build(CacheLoader)} instead, if it is feasible to implement a
551 * {@code CacheLoader}.
552 *
553 * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be
554 * invoked again to create multiple independent caches.
555 *
556 * @return a cache having the requested features
557 * @since 11.0
558 */
559 public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
560 checkWeightWithWeigher();
561 checkNonLoadingCache();
562 return new LocalCache.LocalManualCache<K1, V1>(this);
563 }
564
565 private void checkNonLoadingCache() {
566 checkState(refreshNanos == UNSET_INT, "refreshAfterWrite requires a LoadingCache");
567 }
568
569 private void checkWeightWithWeigher() {
570 if (weigher == null) {
571 checkState(maximumWeight == UNSET_INT, "maximumWeight requires weigher");
572 } else {
573 if (strictParsing) {
574 checkState(maximumWeight != UNSET_INT, "weigher requires maximumWeight");
575 } else {
576 if (maximumWeight == UNSET_INT) {
577 logger.log(Level.WARNING, "ignoring weigher specified without maximumWeight");
578 }
579 }
580 }
581 }
582
583 /**
584 * Returns a string representation for this CacheBuilder instance. The exact form of the returned
585 * string is not specified.
586 */
587 @Override
588 public String toString() {
589 MoreObjects.ToStringHelper s = MoreObjects.toStringHelper(this);
590 if (initialCapacity != UNSET_INT) {
591 s.add("initialCapacity", initialCapacity);
592 }
593 if (concurrencyLevel != UNSET_INT) {
594 s.add("concurrencyLevel", concurrencyLevel);
595 }
596 if (maximumSize != UNSET_INT) {
597 s.add("maximumSize", maximumSize);
598 }
599 if (maximumWeight != UNSET_INT) {
600 s.add("maximumWeight", maximumWeight);
601 }
602 if (expireAfterWriteNanos != UNSET_INT) {
603 s.add("expireAfterWrite", expireAfterWriteNanos + "ns");
604 }
605 if (expireAfterAccessNanos != UNSET_INT) {
606 s.add("expireAfterAccess", expireAfterAccessNanos + "ns");
607 }
608 if (keyStrength != null) {
609 s.add("keyStrength", Ascii.toLowerCase(keyStrength.toString()));
610 }
611 if (valueStrength != null) {
612 s.add("valueStrength", Ascii.toLowerCase(valueStrength.toString()));
613 }
614 if (keyEquivalence != null) {
615 s.addValue("keyEquivalence");
616 }
617 if (valueEquivalence != null) {
618 s.addValue("valueEquivalence");
619 }
620 if (removalListener != null) {
621 s.addValue("removalListener");
622 }
623 return s.toString();
624 }
625 }
626